﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;

namespace TicketSellingServer
{
    [ServiceContract]
    public interface ITicketSellingService
    {
        [OperationContract]
        List<AvailableFlight> GetAvailableFlights(string src, string dst, string date);

        [OperationContract]
        string SellTicket(string flightId, string date);

        [OperationContract]
        void CancelTicket(string reservationId);
    }

    public class TicketSellingService : ITicketSellingService
    {
        private readonly object syncLock = new object();

        public List<AvailableFlight> GetAvailableFlights(string src, string dst, string date)
        {
            DateTime dt = GetStringDate(date);

            var result = from f in FlightsDatabase.Flights
                         where f.From == src && f.To == dst && f.Date == dt
                         select new AvailableFlight
                         {
                             FlightId = f.FlightId,
                             AvailableSeats = f.AvailableSeats,
                             Price = f.Price,
                         };

            return result.ToList();
        }

        public string SellTicket(string flightId, string date)
        {
            DateTime dt = GetStringDate(date);

            lock (syncLock)
            {
                var flight = FlightsDatabase.GetFlight(flightId, dt);
                if (flight == null)
                {
                    throw new FaultException("no such flight");
                }

                if (flight.AvailableSeats <= 0)
                {
                    throw new FaultException("no seats available");
                }

                var reservationId = ReservationsDatabase.Reserve(flightId, dt);

                flight.AvailableSeats--;
                
                return reservationId;
            }
        }

        public void CancelTicket(string reservationId)
        {
            lock (syncLock)
            {
                var reservedFlight = ReservationsDatabase.Cancel(reservationId);
                if (reservedFlight == null)
                {
                    throw new FaultException("no such reservation");
                }

                var flight = FlightsDatabase.GetFlight(reservedFlight.FlightId, reservedFlight.Date);
                if (flight != null)
                {
                    flight.AvailableSeats++;
                }
            }
        }

        private static DateTime GetStringDate(string date)
        {
            DateTime dt;
            try
            {
                dt = Flight.DateFromString(date);
            }
            catch (FormatException)
            {
                throw new FaultException("invalid date format");
            }

            return dt;
        }
    }
}
